11wk-1: Choropleth (folium)

folium
Author

최규빈

Published

November 13, 2023

1. 강의영상

2. Imports

# !pip install folium
import numpy as np
import pandas as pd
#---#
import folium 
import json 
import requests 

3. Dictionary: view vs copy

- 원하지 않는 코드

dct1 = {'a':1, 'b':2, 'c':3}
dct1
{'a': 1, 'b': 2, 'c': 3}
dct2 = dct1 # 복사를 함...
dct1, dct2
({'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2, 'c': 3})
dct2['c'] = 999 
dct1, dct2
({'a': 1, 'b': 2, 'c': 999}, {'a': 1, 'b': 2, 'c': 999})

- 원하는 코드

dct1 = {'a':1, 'b':2, 'c':3}
dct1
{'a': 1, 'b': 2, 'c': 3}
dct2 = dct1.copy() # 복사를 함...
dct1, dct2
({'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2, 'c': 3})
dct2['c'] = 999 
dct1, dct2
({'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'b': 2, 'c': 999})

혹시 좀 더 자세한 내용이 궁금하다면 아래를 참고하세요!!!

https://guebin.github.io/PP2023/posts/2023-06-21-13wk-1.html

4. Choropleth map

- 코로플레스 맵의 예시

- 대충 정의하면, coropleth = polygon + y 이라고 볼 수 있다.

  • polygon은 지리적구역을 표현
  • y는 해당지리적 구역에 대응하는 측정값

5. folium 기본

- 개념

  • Map Object를 생성 (fig 생성)
  • Map Object에 이것저것 추가 (geom 추가)

A. folium.Map()

# 예시1 – 기본, scrollWheelZoom

m = folium.Map(
    scrollWheelZoom = False
)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

# 예시2 – location, zoom_start

m = folium.Map(
    scrollWheelZoom = False,
    location = [36,127],
    zoom_start=6
)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

# 예시3 – 전북대학교 분수대

- location은 구글맵스에서 분수대 좌표를 확인할 것

- zoom_start=18 로 설정할 것

m = folium.Map(
    scrollWheelZoom = False,
    location = [35.8468,127.1294],
    zoom_start=18
)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

B. folium.Marker()

# 예제1MapMarker를 추가

1. Map의 인스턴스와 Marker의 인스턴스를 각각 생성

m = folium.Map(
    scrollWheelZoom = False,
    location = [35.8468,127.1294],
    zoom_start=18
)
marker = folium.Marker(
    location = [35.8468,127.1294]
)

2. 현재는 Map 인스턴스에 Marker 인스턴스가 표시되어있지 않음

m
Make this Notebook Trusted to load map: File -> Trust Notebook

3. Marker 인스턴스를 Map에 추가함

marker.add_to(m)
<folium.map.Marker at 0x7fe459025a50>

4. 이제는 Map 인스턴스에 Marker 인스턴스가 add_to 되어서 함께 표시됨

m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

# 예제2 – 통계학과 대학원생의 산책경로

통계학과 대학원생의 산책로를 마커로 표시하라. 산책경로는 아래와 같다고 하자.

## 통계학과 대학원생의 산책경로..
[35.8471, 127.1291]
[35.8468, 127.1289]
[35.84635, 127.1291]
[35.84635, 127.1297]
[35.8468, 127.12995]
[35.8474, 127.1300]
m = folium.Map(
    scrollWheelZoom = False,
    location = [35.8468,127.1294], zoom_start=18
)
folium.Marker(
    location = [35.8471, 127.1291]
).add_to(m)
folium.Marker(
    location = [35.8468, 127.1289]
).add_to(m)
folium.Marker(
    location = [35.84635, 127.1291]
).add_to(m)
folium.Marker(
    location = [35.84635, 127.1297]
).add_to(m)
folium.Marker(
    location = [35.8468, 127.12995]
).add_to(m)
folium.Marker(
    location = [35.8474, 127.1300]
).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

C. folium.Polygon

# 예제1 – 통계학과 대학원생의 산책경로를 폴리곤으로 표시 (더블리스트)

m = folium.Map(
    scrollWheelZoom = False,
    location = [35.8468,127.1294], zoom_start=18
)
folium.Polygon(
    locations = [[35.8471, 127.1291],
                 [35.8468, 127.1289],
                 [35.84635, 127.1291],
                 [35.84635, 127.1297],
                 [35.8468, 127.12995],
                 [35.8474, 127.1300]]
).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

# 예제2 – 2개의 폴리곤으로 표시 (3중리스트)

poly = np.array([[35.8471, 127.1291],
                 [35.8468, 127.1289],
                 [35.84635, 127.1291],
                 [35.84635, 127.1297],
                 [35.8468, 127.12995],
                 [35.8474, 127.1300]])
lat, lon = poly.T
poly2 = np.stack([lat, lon + 0.0011],axis=1)
poly2
array([[ 35.8471 , 127.1302 ],
       [ 35.8468 , 127.13   ],
       [ 35.84635, 127.1302 ],
       [ 35.84635, 127.1308 ],
       [ 35.8468 , 127.13105],
       [ 35.8474 , 127.1311 ]])
np.stack([poly,poly2],axis=0)
array([[[ 35.8471 , 127.1291 ],
        [ 35.8468 , 127.1289 ],
        [ 35.84635, 127.1291 ],
        [ 35.84635, 127.1297 ],
        [ 35.8468 , 127.12995],
        [ 35.8474 , 127.13   ]],

       [[ 35.8471 , 127.1302 ],
        [ 35.8468 , 127.13   ],
        [ 35.84635, 127.1302 ],
        [ 35.84635, 127.1308 ],
        [ 35.8468 , 127.13105],
        [ 35.8474 , 127.1311 ]]])
m = folium.Map(
    scrollWheelZoom = False,
    location = [35.8468,127.1294], zoom_start=18
)
folium.Polygon(
    locations = np.stack([poly,poly2],axis=0)
).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

아이디어: 이걸 잘 이용하면 코로플레스맵처럼 지도를 행정구열별로 나눌 수 있겠음. 그런데, 실제 구현하려면 엄청난 노가다를 해야할 것으로 생각됨 –> 누군가 해놓지 않았을까??

#

axis를 설정하는 방법을 다시 공부하고 싶다면 https://guebin.github.io/PP2023/posts/02_DataScience/2023-04-12-6wk-2.html#넘파이-공부-4단계-축 을 참고하세요!

6. South Korea github

A. github 소개

- github account: southkorea

- repo: southkorea-maps

- 저장소 https://github.com/southkorea/southkorea-maps 에는 kostat/2028/json/이라는 폴더가 있으며 여기에는 아래의 파일들이 있음.

skorea-municipalities-2018-geo.json # <-- 이 파일에 관심있음. 
skorea-municipalities-2018-topo-simple.json
skorea-municipalities-2018-topo.json
skorea-provinces-2018-geo.json # <-- 이 파일에 관심있음.
skorea-provinces-2018-topo-simple.json
skorea-provinces-2018-topo.json
skorea-submunicipalities-2018-geo.json
skorea-submunicipalities-2018-topo-simple.json
skorea-submunicipalities-2018-topo.json

이중에서 우리는 아래의 두 파일에 관심있음.

skorea-municipalities-2018-geo.json 
skorea-provinces-2018-geo.json 

- 이 파일들에는 행정구역을 의미하는 폴리곤을 누군가가 정리해둠!!

B. json 파일 다운로드

global_dict = json.loads(requests.get('https://raw.githubusercontent.com/southkorea/southkorea-maps/master/kostat/2018/json/skorea-provinces-2018-geo.json').text)
local_dict = json.loads(requests.get('https://raw.githubusercontent.com/southkorea/southkorea-maps/master/kostat/2018/json/skorea-municipalities-2018-geo.json').text)

C. json 파일의 구조

- global_dict의 구조를 살펴보면 아래와 같음

level_0 level_1 level_2 level3 level4
type ‘FeatureCollection’
features [0] type ‘Feature’
geometry type ‘Polygon’
coordinates (1,??,2) list
properties name ‘서울특별시’
base_year ‘2018’
name_eng ‘Seoul’
code ‘11’
[16] type ‘Feature’
geometry type ‘MultiPolygon’
coordinates (6,1,??,2) list
properties name ‘’제주특별자치도’
base_year ‘2018’
name_eng ‘Jeju-do’
code ‘39’
name ‘sido’
crs type ‘name’
properties name ‘urn:ogc:def:crs:OGC:1.3:CRS84’

- local_dict의 구조를 살펴보면 아래와 같음

level_0 level_1 level_2 level3 level4
type ‘FeatureCollection’
features [0] type ‘Feature’
geometry type ‘MultiPolygon’
coordinates (1,1,??,2) list
properties name ‘종로구’
base_year ‘2018’
name_eng ‘Jongno-gu’
code ‘11010’
[249] type ‘Feature’
geometry type ‘MultiPolygon’
coordinates (10,1,??,2) list
properties name ‘서귀포시’
base_year ‘2018’
name_eng ‘Seogwipo-si’
code ‘39020’
name ‘sido’
crs type ‘name’
properties name ‘urn:ogc:def:crs:OGC:1.3:CRS84’

- 포인트는 여기에 있음

poly = np.array(global_dict['features'][0]['geometry']['coordinates'])[0]
lon, lat = poly.T 
np.stack([lat,lon],axis=1)
array([[ 37.69972082, 127.02214829],
       [ 37.69958053, 127.02531549],
       [ 37.70025114, 127.02689807],
       ...,
       [ 37.70145528, 127.01541539],
       [ 37.70101742, 127.01982736],
       [ 37.69972082, 127.02214829]])

- 서울의다각형을 의미하는것 같음. –> 확인해보자.

m = folium.Map(
    location = [37.55,127], 
    zoom_start=11,
    scrollWheelZoom = False
)
folium.Polygon(
    locations= np.stack([lat,lon],axis=1),
    fill=True
).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

일상언어에서는 (lat,lon) 순서로 표현한다. 즉 적도를 기준으로 얼마나 위/아래로 있는지, 그리고 그리니치천문대를 기준으로 얼마나 동/서로 있는지를 표현한다. 그런데 lat이 y축의 느낌을 가지고 lon이 x축의 느낌을 가지는데 (lat,lon) 순으로 좌표를 선택하면 컴퓨터로 표현하기에 종종 헷갈릴 수 있다. 그래서 어떤 경우는 (lon,lat) 순서로 좌표를 정리하기도 한다.

7. folium.Choropleth 를 이용한 시각화

A. folium.Choropleth 소개

- folium.Choropleth 은 아래와 같은 방식으로 그림을 그린다고 생각하면 편리하다. (실제로 이런지는 모르겠음.. 아마 그럴거에요..)

  1. json 파일을 바탕으로 폴리곤을 그린다. 폴리곤에 이름을 붙인다.
  2. df = [폴리곤의이름, 통계값(y)]와 같은 형식으로 정리된 데이터프레임을 바탕으로, 각 폴리곤에 대응하는 y값을 색깔로 맵핑한다.

- 포인트: 2개의 정보를 이용하네?

B. Polygon 시각화

# 예제1 – 전국의 행정구역 시각화 (global)

m = folium.Map(
    location = [36,128],
    zoom_start = 7,
    scrollWheelZoom= False
)
folium.Choropleth(
    geo_data=global_dict
).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

#

# 예제2 – 전국의 행정구역 시각화 (local)

m = folium.Map(
    location = [36,128],
    zoom_start = 7,
    scrollWheelZoom= False
)
folium.Choropleth(
    geo_data=local_dict
).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook